﻿using MC;
using Newtonsoft.Json;
using Station.Common.Rejudgment;
using Station.Inspect.Rejudgment;
using Station.Inspect.SuaModel;
using Station.Inspect.UI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Vision.Camera.Base;
using Vision.Common;
using Vision.Common.Common;

namespace Station.Inspect
{
    public class StaInspect
    {
        public const int IMAGE_WIDTH = 4096;
        public const int IMAGE_HEIGHT = 3000;
        public event EventHandler OnImageChanged;
        public event EventHandler OnSketchChanged;
        public event EventHandler<ErrListEventArgs> OnRejuding;
        public event EventHandler<WorkModeEventArgs> OnWorkModeChanged;
        public event EventHandler<ResultEventArgs> OnInspectFinished;
        public event EventHandler<string> OnChangeSetting;
        public event EventHandler<bool> OnChangeLine;
        public event EventHandler OnReLoadSetting;
        public event EventHandler<bool> OnChangeBaoFei;
        private StaInspect()
        {
            //var c = errDic.ContainsKey("A");
            //errDic["A"] = new ErrList("A", new List<NodeComponent>());
            //errDic["B"] = new ErrList("A", new List<NodeComponent>());
            //errDic.Clear();
            prjList = new List<Project>();
            var prj = new Project()
            {
                LineMode = 1,
                FaceName = "A"
            };
            prjList.Add(prj);
            prj = new Project()
            {
                LineMode = 1,
                FaceName = "B"
            };
            prjList.Add(prj);
            SwitchPrj(0);
        }
        //-------- 轨道1
        private static StaInspect instance;
        private static object instanceLock = new object();

        public static StaInspect Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (instanceLock)
                    {
                        if (instance == null)
                        {
                            instance = new StaInspect();
                        }
                    }
                }
                return instance;
            }
        }
        //--------- 轨道2
        public bool RejudgEnable { get; set; }

        #region 项目
        public InspectConfig config = new InspectConfig();
        private List<Project> prjList;
        public List<Project> PrjList { get => prjList; }
        //private Project prj;
        public int prjID;
        public int PrjID { get => prjID; }
        public Project Prj { get => prjList[prjID]; }
        public bool IsBanYun2 { get; set; } = false;


        public double code2x;
        public double code2y;
        public double code2r;
        //
        public int passcount { get; set; }
        public int goodcount { get; set; }
        public int checkcount { get; set; }
        public int defectcount { get; set; }
        //
        public int apasscount { get; set; }
        public int bpasscount { get; set; }
        public int agoodcount { get; set; }
        public int bgoodcount { get; set; }
        public int adefectcount { get; set; }
        public int bdefectcount { get; set; }
        public int acheckcount { get; set; }
        public int bcheckcount { get; set; }

        /// <summary>
        /// 切换检测项目
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool SwitchPrj(int id, int tt = 0)
        {
            IsMarkBaofei = false;
            IsBaofei = false;

            if (id < 0 || id >= prjList.Count)
                return false;
            if (tt > 0)
            {
                IsBanYun2 = true;
            }
            else
            {
                IsBanYun2 = false;
            }
            if (prjID != id)
            {
                prjID = id;

                Rbt.Pixel2mm.x = Prj.Pixel2mm.x;
                Rbt.Pixel2mm.y = Prj.Pixel2mm.y;
                Rbt.Pixel2mm.z = Prj.Pixel2mm.z;
                if (id == 0 && tt == 0)
                {
                    code2x = StaConfig.Instance.codex1;
                    code2y = StaConfig.Instance.codey1;
                    code2r = StaConfig.Instance.coder1;
                    lightProc(StaConfig.Instance.brightnessTop1);
                    Prj.sketchOrig = StaConfig.Instance.PosA1;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgTopZ1;
                }
                else if (id == 1 && tt == 0)
                {
                    lightProc(StaConfig.Instance.brightnessBottom1);
                    Prj.sketchOrig = StaConfig.Instance.PosB1;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgBottomZ1;

                }
                if (tt == 3)
                {
                    code2x = StaConfig.Instance.codex2;
                    code2y = StaConfig.Instance.codey2;
                    code2r = StaConfig.Instance.coder2;

                    lightProc(StaConfig.Instance.brightnessTop2);
                    Prj.sketchOrig = StaConfig.Instance.PosA2;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgTopZ2;
                }
                if (tt == 4)
                {
                    lightProc(StaConfig.Instance.brightnessBottom2);
                    Prj.sketchOrig = StaConfig.Instance.PosB2;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgBottomZ2;
                }

                //lightProc(Prj.brightness);
                UpdateOrg(Prj.sketchOrig);
                Rbt.MoveAbsAxis(2, Prj.sketchOrig.z, Prj.g_dMaxVel, true);
                OnWorkModeChanged?.Invoke(this, new WorkModeEventArgs(mode, prjID));
                OnChangeLine?.Invoke(this, IsBanYun2);
                OnSketchChanged?.Invoke(this, EventArgs.Empty);
            }
            return true;
        }

        public void initSwitch(int id, int tt = 0)
        {
            IsMarkBaofei = false;
            IsBaofei = false;
            if (id < 0 || id >= prjList.Count)
                return;

            if (tt > 0)
            {
                IsBanYun2 = true;
            }
            else
            {
                IsBanYun2 = false;
            }
            OnChangeLine?.Invoke(this, IsBanYun2);
            if (true)
            {
                prjID = id;
                Rbt.Pixel2mm.x = Prj.Pixel2mm.x;
                Rbt.Pixel2mm.y = Prj.Pixel2mm.y;
                Rbt.Pixel2mm.z = Prj.Pixel2mm.z;
                if (id == 0 && tt == 0)
                {
                    code2x = StaConfig.Instance.codex1;
                    code2y = StaConfig.Instance.codey1;
                    lightProc(StaConfig.Instance.brightnessTop1);
                    Prj.sketchOrig = StaConfig.Instance.PosA1;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgTopZ1;
                }
                else if (id == 1 && tt == 0)
                {
                    lightProc(StaConfig.Instance.brightnessBottom1);
                    Prj.sketchOrig = StaConfig.Instance.PosB1;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgBottomZ1;

                }
                if (tt == 3)
                {
                    code2x = StaConfig.Instance.codex2;
                    code2y = StaConfig.Instance.codey2;
                    lightProc(StaConfig.Instance.brightnessTop2);
                    Prj.sketchOrig = StaConfig.Instance.PosA2;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgTopZ2;
                }
                if (tt == 4)
                {
                    lightProc(StaConfig.Instance.brightnessBottom2);
                    Prj.sketchOrig = StaConfig.Instance.PosB2;
                    Prj.sketchOrig.z = StaConfig.Instance.OrgBottomZ2;
                }

                //lightProc(Prj.brightness);
                UpdateOrg(Prj.sketchOrig);
                Rbt.MoveAbsAxis(2, Prj.sketchOrig.z, Prj.g_dMaxVel, true);
                OnWorkModeChanged?.Invoke(this, new WorkModeEventArgs(mode, prjID));
                OnSketchChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 复位检测
        /// </summary>
        public void ResetPrj()
        {
            errDic.Clear();
        }
        public string loadPath { get; set; }
        public bool Load(string basePath = "", bool isShow = false)
        {
            try
            {
                OnChangeSetting?.Invoke(this, basePath);
                loadPath = basePath;
                Log.Instance.Init(basePath + $"\\SASLog", "", true);

                StaConfig.Instance.Load(basePath);
                StaConfig.Instance.Update();
                string str;
                string path = basePath + $"\\config.json";
                if (File.Exists(path))
                {
                    str = File.ReadAllText(path);
                    var cfg = JsonConvert.DeserializeObject<InspectConfig>(str);
                    if (cfg != null)
                    {
                        config = cfg;
                    }
                }
                str = File.ReadAllText(basePath + "\\staLib.json");
                var nodeLib = JsonConvert.DeserializeObject<List<NodeLib>>(str);
                NodeLibManager.nodeLibs = nodeLib;
                string libpath = basePath + "\\Lib\\Mark";
                Directory.CreateDirectory(libpath);
                foreach (var item in NodeLibManager.nodeLibs)
                {
                    var imgName = basePath + $"\\staLib{item.ID}.bmp";
                    item.Image = (Bitmap)BitmapEx.LoadFromFile(imgName);
                    if (item.IsUseMark)
                    {
                        item.ModelImage = (Bitmap)BitmapEx.LoadFromFile(libpath + $"\\{item.ID}.bmp");
                        if (item.ModelImage != null)
                        {
                            var hcc = new Station.Inspect.SuaModel.ModelScaledShape();
                            hcc.Load(item.ModelImage);
                            item.ModelMark = hcc;
                        }
                        else
                        {
                            MessageBox.Show($"lib{item.ID}mark图像加载失败");
                        }
                    }

                }
                string prjPath = basePath + "\\staInspect2.json";
                if (File.Exists(prjPath))
                {
                    str = File.ReadAllText(prjPath);
                    var prjLst = JsonConvert.DeserializeObject<List<Project>>(str);
                    if (prjLst != null)
                    {
                        foreach (var prj in prjLst)
                            prj.UpdateLib();
                        prjList = prjLst;
                    }
                }
                else
                {
                    prjPath = basePath + "\\staInspect.json";
                    str = File.ReadAllText(prjPath);
                    var prj = JsonConvert.DeserializeObject<Project>(str);
                    if (prj != null)
                    {
                        prj.FaceName = "A";
                        prj.UpdateLib();
                        prjList[0] = prj;
                    }
                }

                UpdateOrg(Prj.sketchOrig);
                var sketchName = basePath + $"\\staSketchA.bmp";
                if (File.Exists(sketchName) == false)
                    sketchName = basePath + $"\\staSketch.bmp";
                prjList[0].sketchImg = (Bitmap)BitmapEx.LoadFromFile(sketchName);
                if (prjList.Count < 3)
                {
                    prjList.Add(prjList[0]);
                }
                sketchName = basePath + $"\\staSketchB.bmp";
                prjList[1].sketchImg = (Bitmap)BitmapEx.LoadFromFile(sketchName);
                if (prjList.Count < 4)
                {
                    prjList.Add(prjList[1]);
                }
                OnSketchChanged?.Invoke(this, EventArgs.Empty);

                StaConfig.Instance.CellNum = config.CellNum;
                StaConfig.Instance.EnableAdjust = config.EnableAdjust;
                StaConfig.Instance.Pixel2mm = prjList[0].Pixel2mm.x;
                StaConfig.Instance.Pixel2mmB = prjList[1].Pixel2mm.x;
                StaConfig.Instance.OrgTopZ1 = prjList[0].sketchOrig.z;
                StaConfig.Instance.OrgBottomZ1 = prjList[1].sketchOrig.z;
                //StaConfig.Instance.PosA1 = prjList[0].sketchOrig;
                //StaConfig.Instance.PosB1 = prjList[1].sketchOrig;
                Rbt.MoveAbsAxis(2, Prj.sketchOrig.z, Prj.g_dMaxVel, true);//控制Z轴动作
                //光源控制
                lightProc(StaConfig.Instance.brightnessTop1);
                //曝光控制
                Instance.Camera.SetExposureTime(StaConfig.Instance.ExposureTime);

                Model.Load(basePath + "\\Model");
                foreach (var prj in prjList)
                {
                    path = basePath + "\\Mark\\" + prj.FaceName;
                    foreach (var item in prj.Marks)
                    {
                        string fileName = path + $"\\{item.ID}.png";
                        if (File.Exists(fileName))
                        {

                            item.Image = (Bitmap)BitmapEx.LoadFromFile(fileName);
                        }

                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Load失败：" + ex.Message);
                return false;
            }
        }


        public void Save(string basePath = "")
        {
            try
            {
                loadPath = basePath;

                string str;
                str = JsonConvert.SerializeObject(config);
                File.WriteAllText(basePath + "\\config.json", str);

                string libpath = basePath + "\\Lib\\Mark";
                Directory.CreateDirectory(libpath);
                str = JsonConvert.SerializeObject(NodeLibManager.nodeLibs);
                File.WriteAllText(basePath + "\\staLib.json", str);
                foreach (var item in NodeLibManager.nodeLibs)
                {
                    item.Image?.Save(basePath + $"\\staLib{item.ID}.bmp");
                    if (item.IsUseMark)
                        item.ModelImage?.Save(libpath + $"\\{item.ID}.bmp");
                }
                prjList[0].sketchOrig1 = prjList[0].sketchOrig;
                prjList[1].sketchOrig1 = prjList[1].sketchOrig;
                string path = basePath + "\\staInspect2.json";
                str = JsonConvert.SerializeObject(prjList);
                File.WriteAllText(path, str);
                prjList[0].sketchImg?.Save(basePath + $"\\staSketchA.bmp");
                prjList[1].sketchImg?.Save(basePath + $"\\staSketchB.bmp");
                foreach (var prj in prjList)
                {
                    path = basePath + "\\Mark\\" + prj.FaceName;
                    Directory.CreateDirectory(path);
                    foreach (var item in prj.Marks)
                    {
                        //string fileName = path + $"\\{item.ID}.png";
                        //if (File.Exists(fileName))
                        //    File.Delete(fileName);
                        //item.Image?.Save(fileName);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Save失败：" + ex.Message);
            }

        }

        //public void Save1()
        //{
        //    try
        //    {
        //        string basePath = Directory.GetCurrentDirectory();
        //        string str = JsonConvert.SerializeObject(NodeLibManager.nodeLibs);
        //        File.WriteAllText(basePath + "\\staLib.json", str);
        //        foreach (var item in NodeLibManager.nodeLibs)
        //        {
        //            item.Image?.Save(basePath + $"\\staLib{item.ID}.bmp");
        //        }
        //        string path = basePath + "\\staInspect.json";
        //        str = JsonConvert.SerializeObject(Prj);
        //        File.WriteAllText(path, str);
        //        Prj.sketchImg?.Save(basePath + $"\\staSketch.bmp");
        //    }
        //    catch (Exception ex)
        //    {
        //        MessageBox.Show("Save失败：" + ex.Message);
        //    }

        //}
        #endregion

        private RobotBase rbt = new RobotBase();
        private ICamera camera;
        public ICamera Camera { get => camera; }
        public object secBmp { get; set; } = new object();
        /// <summary>
        /// 图片锁
        /// </summary>
        public Object CurBmpLock = new object();
        public BmpAndPoint CurBmpPt { get; set; } = null;
        public RobotBase Rbt { get => rbt; }
        public ManualResetEvent RejudgEvent { get; set; } = new ManualResetEvent(true);
        public bool DoRecheck { get => RejudgEvent.WaitOne(0); }
        public bool RecheckClose { set; get; }
        public bool IsCheckOpen { set; get; }
        public bool IsBaofei { set; get; }
        public bool IsPass { set; get; }
        public bool IsMarkBaofei { set; get; }
        public Models Model { get; set; } = new Models();
        //TargetPos pathLTRun;
        //TargetPos pathRTRun;
        //TargetPos pathLBRun;
        //打码模式
        // public int LineMode = { get => Prj.LineMode; };
        public WorkMode mode = WorkMode.AB;
        public WorkMode Mode
        {
            get => mode;
            set
            {
                if (mode != value)
                {
                    errDic.Clear();
                    mode = value;
                    if (mode == WorkMode.OA)
                        if (IsBanYun2)
                        {
                            initSwitch(0, 3);
                        }
                        else
                        {
                            initSwitch(0);
                        }

                    else if (mode == WorkMode.OB)
                    {
                        if (IsBanYun2)
                        {
                            initSwitch(1, 4);
                        }
                        else
                        {
                            initSwitch(1);
                        }
                    }

                    //OnWorkModeChanged?.Invoke(this, new WorkModeEventArgs(WorkMode.AB, prjID));
                }
            }
        }

        public Thread sketchThread;    //缩略图线程
        public Thread inspectThread;   //运动线程
        public Thread EvalThread;      //截图线程
        public Thread SuakitThread;    //检测线程
        /// <summary>
        /// 截图队列
        /// </summary>
        ConcurrentQueue<ErrCamera> EvalCameras = new ConcurrentQueue<ErrCamera>();
        /// <summary>
        /// 检测队列
        /// </summary>
        ConcurrentQueue<ErrCamera> SuakitCameras = new ConcurrentQueue<ErrCamera>();

        AutoResetEvent m_hEventExit = new AutoResetEvent(false);
        public void Bind(ICamera camera, MCLeisai ls)
        {
            this.rbt.Bind(ls);
            this.camera = camera;
        }


        public bool MoveAbsAndReadImage(TargetPos pos, double v)
        {
            Rbt.MoveAbs(pos, v, true);
            Thread.Sleep(Prj.g_nImageTimer);
            return ReadImageOnly();
        }

        public bool ReadImageOnly()
        {
            camera.Snap();
            Bitmap bmp = camera.ReadImage();
            if (bmp == null)
            {
                bmp = new Bitmap(4096, 3000, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            }
            BmpAndPoint bp = new BmpAndPoint();
            bp.bitmap = bmp;
            bp.pos = GetCurPos();
            bp.point = Rbt.TP2PByOrig(bp.pos);
            lock (CurBmpLock)
            {
                CurBmpPt = bp;
            }
            OnImageChanged?.Invoke(this, new EventArgs());
            return this.CurBmpPt.bitmap != null;
        }

        public TargetPos GetCurPos()
        {
            return rbt.GetCurPos();
        }

        public void UpdateOrg(TargetPos pos)
        {
            Prj.sketchOrig = pos;
            Rbt.Orig = pos;
            if (CurBmpPt != null)
            {
                CurBmpPt.point = Rbt.TP2PByOrig(CurBmpPt.pos);
                OnImageChanged?.Invoke(this, new EventArgs());
            }
        }



        public bool IsBusy()
        {
            bool rc = (sketchThread != null && sketchThread.IsAlive) || (inspectThread != null && inspectThread.IsAlive);
            return rc;
        }

        public bool StartMakeSketch()
        {
            if (IsBusy())
            {
                return false;
            }
            sketchThread = new Thread(new ThreadStart(MakeSketchProc));
            sketchThread.IsBackground = true;
            sketchThread.Start();
            return true;
        }
        /// <summary>
        /// 制作缩略图线程
        /// </summary>
        private void MakeSketchProc()
        {
            try
            {
                m_hEventExit.Reset();
                bool bReverse = true;
                Bitmap oldSketch = Prj.sketchImg;
                double dOldSketchProp = Prj.sketchProp;
                Point sz = Rbt.TP2Point(Prj.sketchSize);
                Prj.sketchImg = new Bitmap((int)(sz.X * dOldSketchProp), (int)(sz.Y * dOldSketchProp), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                int nX = sz.X / IMAGE_WIDTH + 1;
                int nY = sz.Y / IMAGE_HEIGHT + 1;
                Graphics g = Graphics.FromImage(Prj.sketchImg);
                g.FillRectangle(Brushes.Red, new Rectangle(0, 0, Prj.sketchImg.Width, Prj.sketchImg.Height));
                bool bok = false;
                int w = (int)(IMAGE_WIDTH * dOldSketchProp);
                int h = (int)(IMAGE_HEIGHT * dOldSketchProp);
                for (int i = 0; i < nY; i++)
                {
                    bReverse = !bReverse;
                    for (int j = 0; j < nX; j++)
                    {
                        if (m_hEventExit.WaitOne(0))
                            goto EXIT_SKETCH;
                        int tJ = bReverse ? (nX - j - 1) : j;
                        Point curPt = new Point(tJ * IMAGE_WIDTH + IMAGE_WIDTH / 2, i * IMAGE_HEIGHT + IMAGE_HEIGHT / 2);
                        TargetPos pos = Rbt.P2TPByOrig(curPt);
                        MoveAbsAndReadImage(pos, Prj.g_dMaxVel);
                        lock (secBmp)
                        {
                            int x = tJ * w;
                            int y = i * h;
                            Rectangle destRect = new Rectangle(x, y, w, h); //输出到图像中的目标区域
                            g.DrawImage(CurBmpPt.bitmap, destRect, new RectangleF(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT), GraphicsUnit.Pixel);
                        }
                        OnSketchChanged?.Invoke(this, EventArgs.Empty);
                    }
                }
                bok = true;
                EXIT_SKETCH:
                if (bok == false)
                {
                    Prj.sketchImg = oldSketch;
                }
                return;

            }
            catch (Exception ex)
            {

            }
        }

        public bool StartInspect()
        {
            if (IsBusy())
                return false;
            inspectThread = new Thread(new ThreadStart(InspectProc));
            inspectThread.IsBackground = true;
            inspectThread.Start();
            return true;
        }
        Dictionary<string, ErrList> errDic { get; set; } = new Dictionary<string, ErrList>();
        ErrList errLst;
        void GenPath(/*List<ErrCell> cells*/)
        {

        }

        public double codeAngle { set; get; }
        bool FindMark(NodeMark nodeMark, out PointF ptOld, out PointF ptOff, out float angle)
        {
            //NodeMark nodeMark = Prj.Marks[0];
            var rect = nodeMark.Rect;
            ptOld = new PointF(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
            var pt = Rbt.P2TPByOrig(ptOld);
            MoveAbsAndReadImage(pt, Prj.g_dMaxVel);
            lock (secBmp)
            {
                nodeMark.SrcImage = (Bitmap)this.CurBmpPt.bitmap.Clone(new Rectangle(2048 - rect.Width / 2 - nodeMark.Dx, 1500 - rect.Height / 2 - nodeMark.Dy, rect.Width + nodeMark.Dx * 2, rect.Height + nodeMark.Dy * 2), CurBmpPt.bitmap.PixelFormat);
            }
            //PointF imgPt;
            double imgAngle;
            bool res = nodeMark.Model.Find(nodeMark.SrcImage, out ptOff, out imgAngle);
            angle = (float)imgAngle;
            codeAngle = angle;
            if (res == false || Math.Abs(imgAngle) > nodeMark.AngleLimit)
            {
                //MessageBox.Show($"{nodeMark.Name}匹配失败");
                IsMarkBaofei = true;
                doChangeBaoFei(false);
                return false;
            }
            nodeMark.StartPoint = new PointF(nodeMark.StartPoint.X + ptOff.X, nodeMark.StartPoint.Y + ptOff.Y);
            PointF centerPt = ptOld;
            centerPt.X += (int)ptOff.X;
            centerPt.Y += (int)ptOff.Y;
            pt = Rbt.P2TPByOrig(centerPt);
            MoveAbsAndReadImage(pt, Prj.g_dMaxVel);
            //Thread.Sleep(10000);
            lock (secBmp)
            {
                nodeMark.DstImage = (Bitmap)this.CurBmpPt.bitmap.Clone();
            }
            return true;
        }
        /// <summary>
        /// 纠偏
        /// </summary>
        //bool AdjustMark()
        //{
        //    //var cells = new List<ErrCell>();
        //    //foreach (var item in Prj.ErrCells)
        //    //{
        //    //    cells.Add(item.DeepCopy());
        //    //}
        //    //cells.Sort((a, b) => (a.Pos.X + a.Pos.Y < b.Pos.X + b.Pos.Y) ?-1:1);
        //    //GenPath(cells);
        //    Prj.Reset();
        //    if (config.EnableAdjust)
        //    {
        //        if (Prj.Marks.Count == 0)
        //        {
        //            IsMarkBaofei=true;
        //            return false;
        //        }
        //        NodeMark nodeMark = Prj.Marks[0];
        //        var rect = nodeMark.Rect;
        //        var centerPt = new PointF(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
        //        var pt = Rbt.P2TPByOrig(centerPt);
        //        MoveAbsAndReadImage(pt, Prj.g_dMaxVel);
        //        lock (secBmp)
        //        {
        //            nodeMark.SrcImage = (Bitmap)this.CurBmpPt.bitmap.Clone(new Rectangle(2048 - rect.Width / 2 - nodeMark.Dx, 1500 - rect.Height / 2 - nodeMark.Dy, rect.Width + nodeMark.Dx * 2, rect.Height + nodeMark.Dy * 2), CurBmpPt.bitmap.PixelFormat);
        //        }
        //        PointF imgPt;
        //        double imgAngle;
        //        bool res = nodeMark.Model.Find(nodeMark.SrcImage, out imgPt, out imgAngle);
        //        if (res == false || Math.Abs(imgAngle) > nodeMark.AngleLimit)
        //        {
        //            IsMarkBaofei = true;
        //            return false;
        //        }
        //        float angle = (float)(-imgAngle * 180 / Math.PI);
        //        Matrix matrix = new Matrix();
        //        matrix.Translate(imgPt.X, imgPt.Y);
        //        matrix.RotateAt(angle, centerPt);//绕局部
        //        PointF[] pts = new PointF[1];
        //        pts[0] = new PointF();
        //        foreach (var comp in Prj.Components)
        //        {
        //            pts[0] = comp.BasePt;
        //            matrix.TransformPoints(pts);
        //            comp.CurPt.Pt = pts[0];
        //            foreach (var ele in comp.Elements)
        //            {
        //                pts[0] = ele.BaseStartPoint;
        //                matrix.TransformPoints(pts);
        //                ele.StartPoint = pts[0];
        //                ele.Angle = ele.BaseAngle + angle;
        //            }
        //        }
        //        centerPt.X += (int)imgPt.X;
        //        centerPt.Y += (int)imgPt.Y;
        //        MoveAbsAndReadImage(pt, Prj.g_dMaxVel);
        //        lock (secBmp)
        //        {
        //            nodeMark.DstImage = (Bitmap)this.CurBmpPt.bitmap.Clone();
        //        }
        //    }
        //    errLst = new ErrList(Prj.FaceName, Prj.Components, Prj.Marks);
        //    return true;
        //}
        bool AdjustMark()
        {
            //var cells = new List<ErrCell>();
            //foreach (var item in Prj.ErrCells)
            //{
            //    cells.Add(item.DeepCopy());
            //}
            //cells.Sort((a, b) => (a.Pos.X + a.Pos.Y < b.Pos.X + b.Pos.Y) ?-1:1);
            //GenPath(cells);
            Prj.Reset();
            if (config.EnableAdjust)
            {
                Matrix matrix = new Matrix();
                float angle;
                if (Prj.Marks.Count == 0)
                {
                    //MessageBox.Show("请先设置Mark点");
                    IsMarkBaofei = true;
                    doChangeBaoFei(false);
                    return false;
                }
                else if (Prj.Marks.Count == 1)
                {
                    PointF centerPt, imgPt;
                    float imgAngle;
                    if (FindMark(Prj.Marks[0], out centerPt, out imgPt, out imgAngle) == false)
                        return false;
                    angle = (float)(-imgAngle * 180 / Math.PI);
                    matrix.Translate(imgPt.X, imgPt.Y);
                    matrix.RotateAt(angle, centerPt);//绕局部
                }
                else
                {
                    PointF oldPt1, offPt1, oldPt2, offPt2;
                    float angle1, angle2;
                    if (FindMark(Prj.Marks[0], out oldPt1, out offPt1, out angle1) == false || FindMark(Prj.Marks[1], out oldPt2, out offPt2, out angle2) == false)
                    {
                        return false;
                    }
                    PointF nPt1 = new PointF(oldPt1.X + offPt1.X, oldPt1.Y + offPt1.Y);
                    PointF nPt2 = new PointF(oldPt2.X + offPt2.X, oldPt2.Y + offPt2.Y);
                    PointF nPt3 = new PointF(oldPt2.X + offPt1.X, oldPt2.Y + offPt1.Y);
                    PointF l31 = new PointF(nPt3.X - nPt1.X, nPt3.Y - nPt1.Y);
                    PointF l21 = new PointF(nPt2.X - nPt1.X, nPt2.Y - nPt1.Y);
                    double aCosA = (l31.X * l21.X + l31.Y * l21.Y) / (Math.Sqrt(l31.X * l31.X + l31.Y * l31.Y) * Math.Sqrt(l21.X * l21.X + l21.Y * l21.Y));
                    if (aCosA > 1)
                        aCosA = 1;
                    else if (aCosA < -1)
                        aCosA = -1;
                    double dir = l31.X * l21.Y - l31.Y * l21.X;
                    double curAngle = Math.Acos(aCosA) * 180 / Math.PI;
                    if (dir < 0)
                        curAngle = -curAngle;
                    angle = (float)curAngle;
                    matrix.Translate(offPt1.X, offPt1.Y);
                    matrix.RotateAt(angle, oldPt1);//绕局部

                    //mark.StartPoint
                }
                PointF[] pts = new PointF[1];
                pts[0] = new PointF();
                //foreach(var mark in Prj.Marks)
                //{
                //    pts[0] = mark.StartPoint;
                //    matrix.TransformPoints(pts);
                //    mark.StartPoint = pts[0];
                //    mark.Angle = mark.BaseAngle + angle;
                //}
                foreach (var comp in Prj.Components)
                {
                    pts[0] = comp.BasePt;
                    matrix.TransformPoints(pts);
                    comp.CurPt.Pt = pts[0];
                    foreach (var ele in comp.Elements)
                    {
                        pts[0] = ele.BaseStartPoint;
                        matrix.TransformPoints(pts);
                        ele.StartPoint = pts[0];
                        ele.Angle = ele.BaseAngle + angle;
                    }
                }

            }
            errLst = new ErrList(Prj.FaceName, Prj.Components, Prj.Marks);
            return true;
        }
        private void ResetProc()
        {
            if (EvalThread != null && EvalThread.IsAlive)
                EvalThread.Abort();
            if (SuakitThread != null && SuakitThread.IsAlive)
                SuakitThread.Abort();
            bEvalExit = false;
            bSuakitExit = false;
        }
        public void AddErrLst(ErrList curLst)
        {
            errDic[curLst.FaceName] = curLst;
            if (curLst.FaceName == "A")
            {
                apasscount = passcount;
                agoodcount = goodcount;
                acheckcount = checkcount;
                adefectcount = defectcount;
            }
            if (curLst.FaceName == "B")
            {
                bpasscount = passcount;
                bgoodcount = goodcount;
                bcheckcount = checkcount;
                bdefectcount = defectcount;
            }


            if (Mode == WorkMode.AB && errDic.ContainsKey("A") && errDic.ContainsKey("B"))
            {
                InspectResult res = new InspectResult(config.CellNum);
                res.Add(errDic["A"]);
                res.Add(errDic["B"]);
                errDic.Clear();
                OnInspectFinished?.Invoke(this, new ResultEventArgs(res));
            }
            else if (Mode == WorkMode.OA && errDic.ContainsKey("A"))
            {
                InspectResult res = new InspectResult(config.CellNum);
                res.Add(errDic["A"]);
                errDic.Clear();
                OnInspectFinished?.Invoke(this, new ResultEventArgs(res));
            }
            else if (Mode == WorkMode.OB && errDic.ContainsKey("B"))
            {
                InspectResult res = new InspectResult(config.CellNum);
                res.Add(errDic["B"]);
                errDic.Clear();
                OnInspectFinished?.Invoke(this, new ResultEventArgs(res));
            }
            else if (IsBaofei || IsPass || IsMarkBaofei)
            {
                InspectResult res = new InspectResult(config.CellNum);
                if (errDic.ContainsKey("A"))
                {
                    res.Add(errDic["A"]);
                }
                if (errDic.ContainsKey("B"))
                {
                    res.Add(errDic["B"]);
                }
                errDic.Clear();
                OnInspectFinished?.Invoke(this, new ResultEventArgs(res));
            }
        }
        private void InspectProc()
        {
            try
            {
                lightProc(Prj.brightness);
                Rbt.MoveAbsAxis(2, Prj.sketchOrig.z, Prj.g_dMaxVel, true);//控制Z轴动作
                ResetProc();
                EvalThread = new Thread(new ThreadStart(EvalProc));
                EvalThread.IsBackground = true;
                EvalThread.Start();
                SuakitThread = new Thread(new ThreadStart(SuakitProc));
                SuakitThread.IsBackground = true;
                SuakitThread.Start();

                if (AdjustMark() == false)
                {
                    IsMarkBaofei = true;
                    return;
                }

                foreach (var camera in errLst.ErrCameras)
                {
                    TargetPos targetPos = Rbt.P2TPByOrig(camera.CPos);
                    MoveAbsAndReadImage(targetPos, Prj.g_dMaxVel);
                    lock (secBmp)
                    {
                        camera.CameraImage = (Bitmap)this.CurBmpPt.bitmap.Clone();
                    }
                    EvalCameras.Enqueue(camera);
                }
                bEvalExit = true;
                while (EvalThread.IsAlive)
                    Thread.Sleep(50);
                bSuakitExit = true;
                while (SuakitThread.IsAlive)
                    Thread.Sleep(50);
                if (RejudgEnable)
                {
                    RejudgEvent.WaitOne();
                    OnRejuding?.Invoke(this, new ErrListEventArgs(errLst, Prj));
                }
                else
                {
                    errLst.SetNG();
                    AddErrLst(errLst);
                    //errLst.Save();
                    IsBaofei = errLst.IsBaofei;
                    if (IsBaofei)
                    {
                        doChangeBaoFei(true);
                    }
                }
                errLst = null;

            }
            catch (Exception ex)
            {

            }
        }

        bool bEvalExit = false;
        bool bSuakitExit = false;

        /// <summary>
        /// 截图线程
        /// </summary>
        public void EvalProc()
        {
            try
            {
                while (bEvalExit == false)
                {
                    ErrCamera camera;
                    Thread.Sleep(50);
                    while (EvalCameras.TryDequeue(out camera))
                    {
                        camera.SplitImage();
                        SuakitCameras.Enqueue(camera);
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// 检测线程
        /// </summary>
        private void SuakitProc()
        {
            try
            {
                while (bSuakitExit == false)
                {
                    ErrCamera camera;
                    Thread.Sleep(50);
                    while (SuakitCameras.TryDequeue(out camera))
                    {
                        foreach (var comp in camera.ErrComponents)
                        {
                            if (comp.Lib == null)
                                continue;
                            var lib = comp.Lib;
                            List<RectErr> res = new List<RectErr>();
                            if (lib.IsUseSeg)
                            {
                                var segRes = Model.RunBswSegModel(comp.Image, comp.MarkID, lib.ID, lib.IsUseSegClass, lib.SegThreshold, lib.SegClassThreshold, lib.SegMinSize, lib.SegMinArea);
                                res.AddRange(segRes);
                            }
                            if (lib.IsUseDefect)
                            {
                                var defRes = Model.RunBswDefect(comp.Image, comp.MarkID, lib.ID, lib.IsUseDefectClass, lib.DefectThreshold, lib.DefectClassThreshold, lib.DefectMinSize, lib.DefectMinArea);
                                res.AddRange(defRes);
                            }
                            //List<RectErr> res = new List<RectErr>();//Prj.
                            //res.Add(new RectErr() { Name = "测试报点", rect = new Rectangle(20, 20, 100, 100), Score = 0.7 });
                            if (comp.ErrCells.Count > 0)
                            {
                                bool bAddCell = false;
                                foreach (var err in res)
                                {
                                    foreach (var cell in comp.ErrCells)
                                    {
                                        if (cell.Rect.IntersectsWith(err.rect))
                                        {
                                            cell.RectErrs.Add(err);
                                            cell.Status = CellStatus.OK;
                                            bAddCell = true;
                                        }
                                    }
                                }
                                if (bAddCell)
                                    errLst.ErrComponents.Add(comp);
                            }
                            else
                            {
                                if (res.Count > 0)
                                {
                                    comp.RectErrs.AddRange(res);
                                    comp.Status = CellStatus.OK;
                                    errLst.ErrLibComponents.Add(comp);
                                }
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {

            }
        }




        public int prjLight { set; get; }

        /// <summary>
        /// 光源控制操作
        /// </summary>
        public void lightProc(int mm)
        {
            byte CalculateLowByteSum(byte[] bytes)
            {
                int sum = 0;
                foreach (byte b in bytes)
                {
                    sum += b;
                }
                return (byte)(sum & 0xFF); // 取低8位
            }
            //--光源控制器
            //StaConfig.Instance.lightCOM = tbCOM.Text.Trim();
            //StaConfig.Instance.lightChannel = int.Parse(tbTongdao.Text);
            //StaConfig.Instance.brightnessTop = int.Parse(tbTopLiang.Text);
            //StaConfig.Instance.brightnessTop = int.Parse(tbBottomLiang.Text);

            SerialPort serialPort = new SerialPort(StaConfig.Instance.lightCOM, 19200); // 指定串口号和波特率

            try
            {
                // 打开串口
                serialPort.Open();

                // 设置串口的一些参数
                serialPort.DataBits = 8; // 数据位数
                serialPort.Parity = Parity.None; // 校验位
                serialPort.StopBits = StopBits.One; // 停止位
                //serialPort.ReadTimeout = 1000; // 设置读取超时时间为1秒
                serialPort.ReadTimeout = 100;



                // 向串口发送数据

                prjLight = mm;

                byte[] dataToSend = new byte[] { 0x40, 0x05, 0x01, 0x00, 0x1A, Convert.ToByte(StaConfig.Instance.lightChannel), Convert.ToByte(mm) };

                byte sumLowByte = CalculateLowByteSum(dataToSend);

                byte[] appendedBytes = dataToSend.Concat(new byte[] { sumLowByte }).ToArray();

                serialPort.Write(appendedBytes, 0, appendedBytes.Length);

                Console.WriteLine("send data: " + appendedBytes);


            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex.Message);

                //AddLog(2, "Error: " + ex.Message);
            }
            finally
            {
                // 关闭串口
                serialPort.Close();
                serialPort.Dispose();
            }
        }

        public void ReLoadSetting()
        {
            OnReLoadSetting?.Invoke(this, EventArgs.Empty);
        }

        public void doChangeBaoFei(bool opp)
        {
            OnChangeBaoFei?.Invoke(this, opp);
        }
        public bool IsCellNGMax;
        public int CellNGCount;
        public string pici;

        //大图制作
        private Bitmap GetCanvas(int n)
        {
            try
            {
                Point sz = Rbt.TP2Point(PrjList[n].sketchSize);
                return new Bitmap((int)(sz.X), (int)(sz.Y), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            }
            catch (Exception)
            {
                return null;
            }
            //Bitmap oldSketch = StaInspect.Instance.PrjList[n].sketchImg;
            //double dOldSketchProp = StaInspect.Instance.PrjList[n].sketchProp;

        }
        public bool isMakeBigImg;
        public Bitmap canvasA;
        public Bitmap canvasB;
        public Graphics gA;
        public Graphics gB;
        public void InitCanvas()
        {
            canvasA = GetCanvas(0);
            canvasB = GetCanvas(1);
            if (canvasB == null || canvasA == null)
            {
                return;
            }
            gA = Graphics.FromImage(canvasA);
            gB = Graphics.FromImage(canvasB);
        }
        public void SaveBigMap(string code)
        {
            if (!isMakeBigImg)
            {
                return;
            }
            if (canvasB == null || canvasA == null)
            {
                return;
            }
            SaveCanvas(canvasA, code, "A");
            SaveCanvas(canvasB, code, "B");
        }
        private void SaveCanvas(Bitmap canvas, string code, string name)
        {
            if (canvasB == null || canvasA == null)
            {
                return;
            }
            try
            {
                if (Mode == WorkMode.OA)
                {
                    if (name == "B")
                    {
                        return;
                    }
                }
                if (Mode == WorkMode.OB)
                {
                    if (name == "A")
                    {
                        return;
                    }
                }
                Image img = canvas;
                string path = "";
                if (string.IsNullOrEmpty(pici))
                {
                    path = $"{loadPath}\\Savemap\\板号-{code}\\big{name}.png";
                }
                else
                {
                    path = $"{loadPath}\\Savemap\\{pici}\\板号-{code}\\big{name}.png";
                }

                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                img.Save(path, ImageFormat.Png);
                img.Dispose();
            }
            catch (Exception)
            {

            }

        }
    }

    public class ErrListEventArgs : EventArgs
    {
        public ErrListEventArgs(ErrList errLst, Project prj)
        {
            Prj = prj;
            ErrLst = errLst;
        }
        public Project Prj { get; set; }
        public ErrList ErrLst { get; set; }
    }

    public class WorkModeEventArgs : EventArgs
    {
        public WorkModeEventArgs(WorkMode mode, int prjID)
        {
            Mode = mode;
            PrjID = prjID;
        }
        public WorkMode Mode { get; set; }
        public int PrjID { get; set; }
    }

    public class ResultEventArgs : EventArgs
    {
        public ResultEventArgs(InspectResult result)
        {
            Result = result;
        }
        public InspectResult Result { get; set; }
    }
    public enum WorkMode
    {
        AB,
        OA,
        OB
    }
    //public class 
}
